﻿namespace LP
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;
    using UnityEngine;
    using System.Threading.Tasks;

    public sealed class UIMgr : AbsMgr, IDontDestroy
    {
        private ResMgr resMgr;
        //当前所有Canvas下关联的界面UIBase对象实例(包括可见和不可见的)
        private Dictionary<Type, UIBase> uiInsDic = new Dictionary<Type, UIBase>();
        //UI id生成器
        private IDGenerator uiIdGenerator = new IDGenerator();
        //所有ui画布类型
        private Dictionary<EUIType, Transform> UICanvasDic = new Dictionary<EUIType, Transform>();
        private Transform uiRootTrans;
        public Camera UICamera { get; private set; }

        private void InitCanvas()
        {
            uiRootTrans = GameObject.Instantiate(resMgr.Load<GameObject>("UIRoot")).transform;
            uiRootTrans.localPosition = Vector3.zero;
            uiRootTrans.localRotation = Quaternion.identity;
            uiRootTrans.localScale = Vector3.one;
            string[] canvasNames = Enum.GetNames(typeof(EUIType));
            foreach (var item in canvasNames)
            {
                Transform canvasTrans = GameObject.Find(item).transform;
                Enum.TryParse<EUIType>(item, out EUIType uIType);
                UICanvasDic.Add(uIType, canvasTrans);
                UICamera = uiRootTrans.GetCom<Camera>("UICamera");
            }
            DontDestroy();
        }

        public Transform GetUICanvas(EUIType uIType)
        {
            return UICanvasDic[uIType];
        }

        public override void OnDestroy()
        {
            foreach (var item in uiInsDic.Values)
            {
                item.OnDestroy();
            }
            uiInsDic.Clear();
            UICanvasDic.Clear();
        }

        public override void OnInit()
        {
            resMgr = GLModuleMgr.Ins.RetriveModule<GlobleModule>().RetrieveMgr<ResMgr>();
            InitCanvas();
        }

        public void ShowUI<T>(ITuple tuple = null, Action cb = null) where T : UIBase
        {
            Type type = typeof(T);
            UIBase uIBase;
            if (uiInsDic.ContainsKey(type))
            {
                uIBase = uiInsDic[type];
                if (uIBase.IsShowing == false)
                {
                    uIBase.OnShowBefore();
                    uIBase.OnShow(tuple);
                    cb?.Invoke();
                }
            }
            else
            {
                object[] attributes = type.GetCustomAttributes(typeof(UIAttribute), false);
                UIAttribute uiConfig = attributes[0] as UIAttribute;
                if (uiConfig.IsResources)
                {
                    GameObject goAsset = resMgr.Load<GameObject>(uiConfig.UIPath);
                    GameObject prefabGo = GameObject.Instantiate(goAsset);
                    LoadUI<T>(prefabGo, uiConfig, type, tuple, cb);
                }
                else
                {
                    resMgr.InstantiateAsync(uiConfig.UIPath, null, (go) =>
                           {
                               LoadUI<T>(go, uiConfig, type, tuple, cb);
                           });
                }
            }
        }

        private void LoadUI<T>(GameObject prefabGo, UIAttribute uiConfig, Type type, ITuple tuple = null, Action cb = null) where T : UIBase
        {
            Transform uiTrans = prefabGo.transform;
            uiTrans.SetParent(GetUICanvas(uiConfig.UIType));
            RectTransform rect = uiTrans as RectTransform;
            rect.anchorMin = Vector2.zero;
            rect.anchorMax = Vector2.one;
            rect.pivot = Vector2.one * 0.5F;
            rect.offsetMin = Vector2.zero;
            rect.offsetMax = Vector2.zero;
            rect.localPosition = Vector3.zero;
            rect.localRotation = Quaternion.identity;
            rect.localScale = Vector3.one;
            UIBase uIBase = Activator.CreateInstance(type, uiIdGenerator.Next, uiConfig.UIPath, uiConfig.IsCache, uiTrans, uiConfig.UIType) as T;
            uiInsDic.Add(type, uIBase);
            uIBase.OnInit();
            uIBase.OnInitFinish();
            uIBase.OnShowBefore();
            uIBase.OnShow(tuple);
            cb?.Invoke();
        }

        public void HideUI<T>(ITuple tuple = null) where T : UIBase
        {
            Type type = typeof(T);
            if (uiInsDic.TryGetValue(type, out UIBase uIBase))
            {
                if (uIBase.IsShowing == true)
                {
                    uIBase.OnHideBefore();
                    uIBase.OnHide(tuple);
                    if (uIBase.IsCache == false)
                    {
                        uiInsDic.Remove(type);
                        uIBase.OnDestroy();
                    }
                }
            }
        }

        public override void OnUpdate(float delta)
        {
            base.OnUpdate(delta);
            foreach (var item in uiInsDic.Values)
            {
                if (item.IsUpdate && item.IsShowing)
                {
                    item.OnUpdate(delta);
                }
            }
        }

        public void DontDestroy()
        {
            GameObject.DontDestroyOnLoad(uiRootTrans.gameObject);
        }
    }
}